/* **************************************************
 * Archivo: TP2C1A2010.c                            *
 * Fecha: 04/05/2010                                *
 * Autor: Ariel Liguori                             *
 *                                                  *
 * **************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "TDAListaDestinatarios.h"
#include "TDAClienteCorreo.h"
#include "TDACorreo.h"
#include "TDACanalSeguro.h"
#include "TDAServidorInseguro.h"
#include "logdebug.h"


/* Cantidad de caracteres del alfabeto. */
#define ALPHABET_QTY 26

/* Define el nombre del archivo de log por default. */
#define LOG_FILE "log.txt"

/* Maxima longitud de nombre de archivo permitida */
#define MAX_FILENAME_SIZE 32

/* Extension de los archivos de entrada */
#define DEFAULT_EXTENSION ".txt"

/* Sufijo a agregar para generar los archivos de salida */
#define DEFAULT_SUFFIX "_recv.txt"

/* Longitud del sufijo a agregar (incluye el \0) */
#define SUFFIX_LENGTH 10


void generarClaveRandom(char* clave);
int strEnArray(char auxDest[MAX_QTY_DEST][MAX_ADDR_SIZE], char *destinatario);

int main(int argc, char **argv) {

	/* Declaro las variables que voy a utilizar */
	/* Los clientes de correo */
	TDAClienteCorreo emisor;
	TDAClienteCorreo receptor;
	TDAClienteCorreo *clientesCorreo;

	/* Dos variables para los correos */
	TDACorreo correoEnviado;
	TDACorreo correoRecibido;

	/* El canal seguro */
	TDACanalSeguro canalSeguro;

	/* El servidor */
	TDAServidorInseguro servidor;

	/* Los archivos a importar y exportar */
	FILE* archivoIn;
	FILE* archivoOut;
    FILE* archivoLog;

    char auxDest[MAX_QTY_DEST][MAX_ADDR_SIZE];

    /* Variables empleadas solo en el caso de envio de correo estandar */
    char auxFilename[MAX_ADDR_SIZE];

    TListaSimple ld;
    TListaCorreo lc;
    int qtyEmails=0;
    char clave[MAX_KEY_LEN];

    TDACorreo correoAux;

    /* Variable auxiliar para generar el nombre del archivo final
     * sin la necesidad de modificar argv
     */
    char outFilename[MAX_FILENAME_SIZE];
    int id = 0;
	size_t i,j;

    /* Variables empleadas solo en el caso de envio de correo estandar */
    char remitente[MAX_ADDR_SIZE];
    char destinatario[MAX_ADDR_SIZE];
    char asunto[MAX_SUBJECT_SIZE];
    char cuerpo[MAX_BODY_SIZE];
    time_t fechaHora;



    crearCanalSeguro(&canalSeguro);
    generarClaveRandom(clave);
    setContenido(&canalSeguro, clave);

    crearServidor(&servidor);

    crearClienteCorreo(&emisor,DEFAULT_RMT);
    obtenerClave(&emisor, canalSeguro);

    if ( conectar(&emisor, &servidor) ){
        logmacro("\n%s\n","No fue posible conectar el emisor al servidor");
        return EXIT_FAILURE;
    }


    /* Recorro todos los argumentos, a partir de el segundo elemento
     * se encuentran los argumentos que hacen referencia al nombre del
     * del archivo a abrir.
     * Hago un parse de cada archivo y lo subo como correo valido al
     * server y obtengo la cantidad de destinatarios de cada correo y
     * a la vez la cantidad de destinatarios distintos en total.
     */
    for ( i=0 ; i < argc ; i++){

        if ( argc != 1 ){

            if( !i )
                i++;
            logmacro("\n Abriendo archivo: %s\n\n",argv[i]);
            archivoIn=fopen(argv[i],"r");

            /* Chequeo que el archivo se haya abierto correctamente */
            if ( archivoIn == NULL ){
                logmacro("\nError al abrir archivo: %s\n",argv[i]);
                return EXIT_FAILURE;
            }

            if ( importarDesde(&correoAux, archivoIn) ){
                logmacro("\nError al importar correo: %s\n",argv[i]);
                return EXIT_FAILURE;
            }
            setFilename(&correoAux,argv[i]);

        }else{
        /* Si no hay argumentos se procede al envio del correo estandar por std output. */

            crearCorreo(&correoEnviado);
            printCorreo(correoEnviado);
            setDestinatario(&correoEnviado,DEFAULT_DST);
            printCorreo(correoEnviado);
            crearClienteCorreo(&receptor,DEFAULT_DST);
            obtenerClave(&receptor, canalSeguro);

            if ( enviarCorreo(emisor, correoEnviado) ){
                logmacro("\n%s\n","Error al enviar correo.");
                return EXIT_FAILURE;
            }

            printCorreo(correoEnviado);

            if ( conectar(&receptor, &servidor) ){
                logmacro("\n%s\n","No fue posible conectar el emisor al servidor");
                return EXIT_FAILURE;
            }


            /* Elimino el contenido del canal seguro */
            eliminarContenido(&canalSeguro);

            /* Creo una variable para contener el correo recibido */
            crearCorreo(&correoRecibido);

            if ( recibirProximoCorreo(receptor,&correoRecibido) ){
                return EXIT_FAILURE;
            }

            /* Si no recibi argumentos muestro el correo por salida estandar (segun especificaciones)*/
        	fechaHora = getFechaHoraEnviado(correoRecibido);
            getRemitente(correoRecibido, remitente);

            ldest_Crear(&ld, sizeof(destinatario) );
            getDestinatarios(correoRecibido, &ld);
            ldest_MoverCorriente(&ld, LS_PRIMERO);
            ldest_ElemCorriente(ld,destinatario);

            getAsunto(correoRecibido, asunto);
            getTextoCuerpo(correoRecibido, cuerpo);

            printf("From: %s\n",remitente);
            printf("To: %s\n",destinatario);
            printf("Subject: %s\n",asunto);
            printf("Date: %s\n",ctime(&fechaHora));
            printf("%s\n",cuerpo);

            desconectar(&emisor);
            desconectar(&receptor);

            destruirServidor(&servidor);

            destruirCorreo(&correoRecibido);
            destruirCorreo(&correoEnviado);
            destruirCanalSeguro(&canalSeguro);
            destruirClienteCorreo(&emisor);
            destruirClienteCorreo(&receptor);

            archivoLog=fopen(LOG_FILE,"w");
            escribirLog(servidor,archivoLog);

            return EXIT_SUCCESS;

        }

        if ( enviarCorreo(emisor, correoAux) ){
            logmacro("\n%s\n","Error al enviar correo.");
            return EXIT_FAILURE;
        }

        logmacro("%s\n", "Enviando correo");

        for ( j = 0; j < getCantidadDestinatarios(correoAux) ; j++){

            getDestinatarioX(&correoAux,destinatario,j);

            if ( !strEnArray(auxDest,destinatario) || !id ){
                strcpy(auxDest[id],destinatario);
                id++;
            }

        }

    }

    logmacro("\n\nCantidad de destinatarios diferentes: %d",id);


    /* Reservo memoria para la cantidad de clientes de correo correspondiente
     * a la cantidad de destinatarios diferentes que encontre.
     */
    clientesCorreo = (TDAClienteCorreo*) malloc( (id*sizeof(TDAClienteCorreo)) );

    if (clientesCorreo == NULL){
        logmacro("%s\n","No hay memoria disponible en el sistema");
        return EXIT_FAILURE;
    }


    /* Obtengo la clave, seteo la direccion del dest. y conecto al server*/
    for ( j=0 ; j < id ; j++){
        crearClienteCorreo(&(clientesCorreo[j]),auxDest[j]);
        obtenerClave(&(clientesCorreo[j]), canalSeguro);

        if ( conectar(&(clientesCorreo[j]), &servidor) ){
            logmacro("\n%s\n","No fue posible conectar el emisor al servidor");
            return EXIT_FAILURE;
        }


    }

    /* Elimino el contenido del canal seguro */
    eliminarContenido(&canalSeguro);

    /* Creo una variable para contener el correo recibido */
    crearCorreo(&correoRecibido);



    for ( j = 0; j < id ; j++) {

        qtyEmails = obtenerTodos(clientesCorreo[j],&lc);

        if ( !qtyEmails ){
            logmacro("\n%s\n","No hay emails recibidos.");
            return EXIT_FAILURE;
        }

        LC_MoverCorriente(&lc, LO_PRIMERO);

        for( i=0; i < qtyEmails ; i++){

            LC_ObtenerCorriente(lc, &correoRecibido);
            LC_MoverCorriente(&lc, LO_SIGUIENTE);

            getFilename(correoRecibido,outFilename);

            /* Defino el nombre del archivo a grabar segun lo especificado en el TP. */
            strcpy(auxFilename,"_");
            strcat(auxFilename,clientesCorreo[j].direccion);
            strcat(auxFilename,".txt");
            memcpy(outFilename+strlen(outFilename)-strlen(DEFAULT_EXTENSION),auxFilename,(strlen(auxFilename)+1));

            /* Guardo el correo en un archivo */
            logmacro("\n Guardando mensaje en el archivo: %s\n\n",outFilename);
            archivoOut=fopen(outFilename,"w");

            /* Chequeo que el archivo se haya abierto correctamente */
            if ( archivoOut == NULL ){
                logmacro("\n%s\n","Error al abrir/crear el archivo de salida.");
                return EXIT_FAILURE;
            }

            if ( escribirA(correoRecibido, archivoOut) ){
                logmacro("\nError al escribir el correo en el archivo: %s",outFilename);
                return EXIT_FAILURE;
            }
        }

        LC_Vaciar(&lc);
    }

    /* Abro el archivo de logs y guardo la data del server. */
    archivoLog=fopen(LOG_FILE,"w");
    escribirLog(servidor,archivoLog);

    /* Descpnecto los clientes de correo receptores */
    for ( j=0 ; j < id ; j++){
        desconectar( &(clientesCorreo[j]) );
        destruirClienteCorreo( &(clientesCorreo[j]) );
    }

    /* Libero la memoria asignada a cada clienteCorreo */
    free(clientesCorreo);

    /* Destruyo las variables que use para los correos */
    destruirCorreo(&correoRecibido);
    destruirCorreo(&correoAux);

    /* Desconecto el emisor del servidor */
    desconectar(&emisor);

    /* Destruyo los clientes, el canal seguro y el servidor */
    destruirCanalSeguro(&canalSeguro);
    destruirClienteCorreo(&emisor);
    destruirServidor(&servidor);



	logmacro("%s\n", "Simulacion finalizada");

	return EXIT_SUCCESS;
}




int strEnArray(char auxDest[MAX_QTY_DEST][MAX_ADDR_SIZE], char *destinatario){

    int i=0;

    for( ; i < MAX_QTY_DEST ; i++){
        if ( !strcmp(auxDest[i], destinatario) ){
            return 1;
        }
    }

    return 0;
}


void generarClaveRandom(char* clave){

    size_t i=0;
    int keyLen;

    /* Seteo la semilla en un valor random */
    srand((unsigned)time(NULL));

    /* Hago que la longitud de la clave sea random entre 1 y 31 */
    keyLen = (( rand() % (MAX_KEY_LEN - 1) ) + 1);

    /* Re-Seteo la semilla en un valor random */
    srand((unsigned)time(NULL));

    for( ; i<=keyLen ; i++)
        clave[i] = ( ( rand() % ALPHABET_QTY ) + 65 );

    /* Agrego \0 al final para convertirlo en un string valido */
    clave[i] = '\0';

}



